package framework

import (
	"context"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"log/slog"
	"mortnon-go/app/common"
	"mortnon-go/app/common/web"
	"mortnon-go/app/config"
	"mortnon-go/app/framework/middleware"
	"net/http"
	"os"
	"os/signal"
	"time"
)

var Routers = make([]func(), 0)

func StartServer(env config.Environment) error {
	// 1. 读取配置文件
	if err := loadConfig(env); err != nil {
		slog.Error("读取配置文件失败，错误原因：", err)
		return err
	}

	// 3. 初始化中间件
	if err := initMiddleWare(); err != nil {
		slog.Error("初始化gin中间件失败, 错误信息：", err)
		return err
	}

	// 4. init router 初始化路由信息
	if err := initRouters(); err != nil {
		slog.Error("初始化路由信息失败, 错误信息:", err)
		return err
	}

	// 5. shutdown，关机
	shutdown()

	return nil
}

// 初始化路由信息
func initRouters() error {
	// TODO 完成初始化router
	engine := Context.GetEngine()
	// 转换为路由
	router := engine.(*gin.Engine)

	router.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"success": true, "message": "pong"})
	})

	return nil
}

func initMiddleWare() error {
	engine := Context.GetEngine()
	router := engine.(*gin.Engine)

	router.Use(gin.Logger(), gin.Recovery())
	router.Use(middleware.TraceId(web.TraceKey))
	return nil
}

// 读取配置文件
func loadConfig(env config.Environment) error {
	// 如果未传入环境，默认为prod环境，防错
	if len(env) == 0 {
		env = config.EnvProd
	}

	if applicationConfig, err := config.LoadConfig(env); err != nil {
		return err
	} else {
		Context.SetEnvironment(env)
		Context.SetConfig(applicationConfig)

		// 初始化gin
		gin.SetMode(config.GetGinModeByEnv(env))
		engine := Context.GetEngine()
		if engine == nil {
			engine = gin.New()
			Context.SetEngine(engine)
		}
	}

	return nil
}

// 优雅关机
func shutdown() {
	engine := Context.GetEngine()

	applicationConfig := Context.GetConfig().Application

	srv := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", applicationConfig.Host, applicationConfig.Port),
		Handler: engine,
	}

	go func() {
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			slog.Error("listen: ", err)
		}
	}()

	slog.Info(common.Green("Server run at:"))
	slog.Info(fmt.Sprintf("-  Env:	%s \r\n", Context.Env))
	slog.Info(fmt.Sprintf("-  EnvLocal:   http://localhost:%d/ \r\n", applicationConfig.Port))
	slog.Info(fmt.Sprintf("-  Network:	http://%s:%d/ \r\n", common.GetLocalHost(), applicationConfig.Port))
	slog.Info(" Enter Control + C Shutdown Server \r\n")

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	slog.Info("Shutdown Server ...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		slog.Info("Server Shutdown:", err)
	}

	slog.Info("Server exiting")
}
